package com.csv2excel;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.*;

public class Csv2Excel implements Runnable {
    private Printer printer = null;
    private String sourceFile;
    private String targetPath;
    private String targetFileName;
    private int maxRowNum=20000;

    /**
     * 创建Csv2Excel对象
     * @param printer 用于打印执行过程信息
     * @param sourceFile 源文件，csv文件，例如：/tmp/csv/test.csv
     * @param targetPath 目标文件路径，不包括文件名，末尾不要分隔符，例如：/tmp/excel
     * @param targetFileName 目标文件名，excel文件，例如：test.xlsx
     */
    public Csv2Excel(Printer printer, String sourceFile, String targetPath, String targetFileName) {
        this.printer = printer;
        this.sourceFile = sourceFile;
        this.targetPath = targetPath;
        this.targetFileName = targetFileName;
    }

    /**
     * 创建Csv2Excel对象
     * @param printer 用于打印执行过程信息
     * @param sourceFile 源文件，csv文件，例如：/tmp/csv/test.csv
     * @param targetPath 目标文件路径，不包括文件名，末尾不要分隔符，例如：/tmp/excel
     * @param targetFileName 目标文件名，excel文件，例如：test.xlsx
     * @param maxRowNum 每个sheet最大行数，如果入参<=0，则取默认值{@link Csv2Excel#maxRowNum}
     */
    public Csv2Excel(Printer printer, String sourceFile, String targetPath, String targetFileName, int maxRowNum) {
        this(printer, sourceFile, targetPath, targetFileName);
        if (maxRowNum>0){
            this.maxRowNum = maxRowNum;
        }
    }

    @Override
    public void run() {
        transform();
    }

    /**
     * 转换
     */
    public void transform(){
        printMsg("开始转换："+sourceFile+" >> "+targetPath+File.separator+targetFileName);

        SXSSFWorkbook workbook = null;
        try {
            workbook=createExcel();
        } catch (FileNotFoundException e) {
            printMsg("转换过程出错，未找到源文件："+sourceFile);
            return;
        } catch (IOException e) {
            printMsg("转换过程出错，："+e);
            return;
        } catch (Exception e) {
            printMsg("转换过程出错，"+e);
            return;
        }

        try {
            printMsg("开始写入目标文件");
            FileOutputStream fos = new FileOutputStream(targetPath+ File.separator+targetFileName);
            workbook.write(fos);
            fos.close();
            printMsg("转换完成");
        } catch (FileNotFoundException e) {
            printMsg("转换过程出错，未找到目标文件路径："+targetPath+File.separator+targetFileName);
        } catch (IOException e) {
            printMsg("转换过程出错，"+e);
        } catch (Exception e) {
            printMsg("转换过程出错，"+e);
        }
    }

    /**
     * 打印信息
     * @param msg
     */
    public void printMsg(String msg){
        if (printer!=null){
            printer.println(msg);
        }
    }

    /**
     * 创建sheet
     * @param workbook excel对象
     * @param titles 表头
     * @return sheet对象
     */
    public Sheet createSheet(SXSSFWorkbook workbook, String[] titles){
        Sheet sheet = workbook.createSheet();
        // 创建表头
        Row head = sheet.createRow(0);
        for(int i=0;i<titles.length;i++){
            head.createCell(i).setCellValue(titles[i]);
        }
        return sheet;
    }

    /**
     * 创建excel对象
     * @return excel对象
     * @throws FileNotFoundException
     * @throws IOException
     */
    public SXSSFWorkbook createExcel() throws FileNotFoundException, IOException {
        printMsg("读取表头");
//        FileReader fileReader = new FileReader(sourceFile);
        InputStreamReader fileReader = new InputStreamReader(new FileInputStream(sourceFile), "UTF-8");
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        String line=bufferedReader.readLine();
        String[] titles = line.split("\t");
        //第一行为表头内容
        printMsg(line);

        XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
        SXSSFWorkbook workbook = new SXSSFWorkbook(xssfWorkbook , 2000);
        Sheet sheet=createSheet(workbook, titles);

        printMsg("读取表数据");
        int lineNum=0;
        int rowNum = 0;
        //数据
        while((line=bufferedReader.readLine())!=null){
            lineNum++;
            rowNum++;
            if (rowNum>1 && rowNum%maxRowNum==1){
                sheet = createSheet(workbook, titles);
                rowNum=1;
            }
            Row row = sheet.createRow(rowNum);
            String[] datas = line.split("\t");
            for (int i=0;i<datas.length;i++){
                row.createCell(i).setCellValue(datas[i]);
            }

            if (lineNum%100==0) {
                printMsg("已读取"+lineNum+"行数据");
            }
        }
        printMsg("已读取"+lineNum+"行数据");
        printMsg("源文件读取完成");
        bufferedReader.close();

        return workbook;
    }
}
